package com.lagou.util;

import com.lagou.bean.MonitorBean;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * <h1>Dubbo性能监控工具类</h1>
 * @author yzh
 */
public class TpMonitorUtil {

    /**
     * 私有成员变量
     */
    private TpMonitorUtil() {

    }

    /**
     * 服务运行时长(从程序第一次执行开始计算,单位为秒)
     */
    private static Long INVOKE_TIME_NUM = 0L;

    /**
     * 方法每次执行情况队列集合:存储每个方法每次执行情况的队列
     */
    private static ConcurrentHashMap<String, PriorityBlockingQueue<MonitorBean>> queueMap;

    /**
     * 获得方法对应的执行情况队列
     * @param methodName
     * @return
     */
    public static PriorityBlockingQueue<MonitorBean> getQueue(String methodName) {
        if(queueMap == null) {
            queueMap = new ConcurrentHashMap<>();
        }
        if(queueMap.get(methodName) == null) {
            queueMap.put(methodName, new PriorityBlockingQueue<>());
            startTpPrint(methodName);
            startQueueAutoRemove(methodName);
        }
        return queueMap.get(methodName);
    }

    /**
     * 开启TP监控指标打印
     * @return
     */
    private static void startTpPrint(String methodName) {
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(5000);
                    PriorityBlockingQueue<MonitorBean> queue = queueMap.get(methodName);
                    MonitorBean[] monitorBeanArr = new MonitorBean[queue.size()];
                    queue.toArray(monitorBeanArr);
                    Double tp90Index = Math.floor(monitorBeanArr.length * 0.9);
                    Double tp99Index = Math.floor(monitorBeanArr.length * 0.99);
                    System.out.println(methodName+"的TP90耗时:"+monitorBeanArr[tp90Index.intValue()].getInvokeTime()+"ms");
                    System.out.println(methodName+"的TP99耗时:"+monitorBeanArr[tp99Index.intValue()].getInvokeTime()+"ms");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 开启队列自动移除:一分钟执行一次,将一分钟前队列中的请求移除,辅助打印线程,保证每次打印前的数据为1分钟内的
     * @return
     */
    private static void startQueueAutoRemove(String methodName) {
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(60000);
                    long tempInvokeTimeNum = INVOKE_TIME_NUM;
                    if(tempInvokeTimeNum > 60) {
                        PriorityBlockingQueue<MonitorBean> queue = queueMap.get(methodName);
                        MonitorBean tempMonitorBean = null;
                        Iterator<MonitorBean> iterator = queue.iterator();
                        while (iterator.hasNext()) {
                            tempMonitorBean = iterator.next();
                            if((tempInvokeTimeNum - tempMonitorBean.getCallNum()) > 60) {
                                queue.remove(tempMonitorBean);
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 获得服务运行时长
     * @return
     */
    public static Long getInvokeTimeNum() {
        return INVOKE_TIME_NUM;
    }

    /**
     * 开启服务运行时长统计
     * @return
     */
    public static void startInvokeTimeNumCount() {
        new Thread(() -> {
            while (true) {
                try {
                    INVOKE_TIME_NUM++;
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}